package com.zxx.dis.lock;

import com.zxx.dis.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Component
public class DistributedRedisLock implements Lock {


    private static final String LOCK_SCRIPT =
            "if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +
                    "   redis.call('hincrby', KEYS[1], ARGV[1], 1) " +
                    "   redis.call('expire', KEYS[1], ARGV[2]) " +
                    "   return 1 " +
                    "else " +
                    "   return 0 " +
                    "end";
    // Redis Lua脚本: 释放锁
    private static final String UNLOCK_SCRIPT =
            "if redis.call('hexists', KEYS[1], ARGV[1]) == 0 then " +
                    "   return 0 " +
                    "else " +
                    "   local count = redis.call('hincrby', KEYS[1], ARGV[1], -1) " +
                    "   if count == 0 then " +
                    "       redis.call('del', KEYS[1]) " +
                    "   end " +
                    "   return 1 " +
                    "end";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private String uuid;
    ThreadLocal<String> uuidThreadLocal = ThreadLocal.withInitial(() -> UUID.randomUUID().toString());

    @Override
    public void lock() {
        System.out.println(uuidThreadLocal.get());
//        ThreadLocal<String> uuidThreadLocal = ThreadLocal.withInitial(() -> UUID.randomUUID().toString());
//        System.out.println(uuidThreadLocal.get());
        tryLock();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        try {
            this.tryLock(-1L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        DefaultRedisScript<Boolean> lockScript = new DefaultRedisScript<>(LOCK_SCRIPT, Boolean.class);

        while(!stringRedisTemplate.execute(
                lockScript,
                Collections.singletonList("lock"),
                uuidThreadLocal.get(),
                "3000"
        )){
            Thread.sleep(100);
        }
//        System.out.print("get-");
//        System.out.println(uuid);
        return false;
    }

    @Override
    public void unlock() {
        DefaultRedisScript<Boolean> unlockScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Boolean.class);
//        System.out.print("del-");
//        System.out.println(uuid);
        Boolean isDeleted = stringRedisTemplate.execute(unlockScript, Collections.singletonList("lock"),uuidThreadLocal.get(),"3000");
        if(isDeleted) System.out.println("1");
        else System.out.println("0");
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
